/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package mp.weixin.WXpublic;

import mp.weixin.WXpublic.group.GroupEntity;
import mp.weixin.WXpublic.kefu.KefuDialog;
import mp.weixin.WXpublic.kefu.KefuDialogList;
import mp.weixin.WXpublic.kefu.SessionKefu;
import mp.weixin.WXpublic.kefu.SessionUser;
import mp.weixin.WXpublic.kefu.WaitingSession;
import mp.weixin.WXpublic.kefu.WaitingSessionList;
import mp.weixin.WXpublic.material.MaterialCount;
import mp.weixin.WXpublic.material.MaterialNews;
import mp.weixin.WXpublic.material.MaterialNewsList;
import mp.weixin.WXpublic.material.MaterialOther;
import mp.weixin.WXpublic.material.MaterialOther.MaterialType;
import mp.weixin.WXpublic.material.MaterialOthers;
import mp.weixin.WXpublic.material.TempMaterial;
import mp.weixin.WXpublic.material.TempMaterial.MediaType;
import mp.weixin.WXpublic.qrcode.QrcodeEntity;
import mp.weixin.WXpublic.qrcode.QrcodeParameter;
import mp.weixin.WXpublic.templatemessage.TemplateData;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringEscapeUtils;
import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.JsonProcessingException;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.node.ObjectNode;
import org.jdom.JDOMException;

import java.util.LinkedList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.codehaus.jackson.JsonParser;
import utils.MD5;
import mp.weixin.WXpublic.kefu.WeiXinKeFuUser;
import org.codehaus.jackson.node.JsonNodeFactory;
import utils.WeiXinUtil;
import static utils.WeiXinUtil.getHttpBackDomStr;

/**
 *
 * @author 王仲秋
 */
public class WeiXinPublic implements Serializable {

    /**
     * 微信接入时使用的 接入后
     */
    private final String TOKEN;
    /**
     * 消息处理对象 整个消息进入 到消息对象的生成
     */
    private final MessageConvert messageConvert = new MessageConvert();
    private final AccessTokenCache atc;
    /**
     * 消息加密的密钥 不使用加密信息的时候 不需要初始化
     */
    private final String ENCODING_ACES_KEY;
    private final String APPID;
    private final String APPSECRET;
    private JSAPITicketCache ticketCache;

    private WeiXinPublic() {
        TOKEN = null;
        ENCODING_ACES_KEY = null;
        APPID = null;
        APPSECRET = null;
        atc = null;
    }

    /**
     *
     * @param token 微信接入时使用的 接入后不再用
     * @param encodingAcesKey 消息加密的密钥 不使用加密信息的时候 不需要初始化
     * @param appId 公众号开发使用
     * @param appSeceret 公众号开发使用
     * @param ml 消息监听接口 配置不同的消息返回
     * @param atc 实现AccessToken 的缓存 可以根据不同情况使用不同的缓存
     * @param ticketCache 更新jsapi ticket的缓存
     */
    public WeiXinPublic(String token, String encodingAcesKey, String appId, String appSeceret, final MessageListener ml, final AccessTokenCache atc, final JSAPITicketCache ticketCache) {
        messageConvert.bindingListener(ml);
        this.TOKEN = token;
        this.ENCODING_ACES_KEY = encodingAcesKey;
        this.APPID = appId;
        this.APPSECRET = appSeceret;
        this.atc = atc;
        if (atc != null) {
            Thread acccessTokenThread = new Thread() {
                int timeDelay = 200;
                //这样设置比微信的时间段 微信默认7200 秒
                int expiresIn = 260 - timeDelay;

                @Override
                public void run() {
                    AccessToken accessToken = new AccessToken();
                    while (true) {
                        int errorCount = 0;
                        if (atc.runable()) {
                            try {
                                JsonNode jsono = getAccessTokenJson();
                                accessToken.accessToken = jsono.get("access_token").getTextValue();
                                accessToken.expiresIn = jsono.get("expires_in").getIntValue();
                                accessToken.expiresTime = System.currentTimeMillis() + (accessToken.expiresIn * 1000);
                                atc.cache(accessToken);
                            } catch (WeixinMessageException ex) {
                                errorCount++;
                                System.out.println(ex.getMessage());
                            } catch (NullPointerException ex) {
                                errorCount++;
                                System.out.println(ex.getMessage());
                                ex.printStackTrace();
                            }
                            if (errorCount == 0) {
                                expiresIn = accessToken.expiresIn - timeDelay;
                            } else {
                                errorCount = 0;
//                                continue;
                            }
                        }
                        try {
                            synchronized (this) {
                                this.wait(expiresIn * 1000);
                            }
                        } catch (InterruptedException ex) {
                            ex.printStackTrace();
                        }
                    }
                }
            };
            acccessTokenThread.start();
        }
        this.ticketCache = ticketCache;
        if (ticketCache != null) {
            Thread jsapitThread = new Thread() {
                int timeDelay = 200;
                //这样设置比微信的时间段 微信默认7200 秒
                int expiresIn = 260 - timeDelay;

                @Override
                public void run() {
                    try {
                        synchronized (this) {

                            //等待accesstoken 更新完毕
                            this.wait(60 * 1000);
                        }
                    } catch (InterruptedException ex) {
                        ex.printStackTrace();
                    }
                    JSAPITicket ticket = new JSAPITicket();
                    while (true) {
                        int errorCount = 0;
                        if (ticketCache.runable()) {
                            try {
                                JsonNode jsono = getJsapiTicketJson();
                                ticket.ticket = jsono.get("ticket").getTextValue();
                                ticket.expiresIn = jsono.get("expires_in").getIntValue();
                                ticket.expiresTime = System.currentTimeMillis() + (ticket.expiresIn - timeDelay) * 1000;
                                ticket.errcode = jsono.get("errcode").getIntValue();
                                ticket.errmsg = jsono.get("errmsg").getTextValue();
                                ticketCache.cache(ticket);
                            } catch (Exception ex) {
                                errorCount++;
                                ex.printStackTrace();
                            }
                            if (errorCount == 0) {
                                expiresIn = ticket.expiresIn - timeDelay;
                            } else {
                                errorCount = 0;
//                                continue;
                            }
                        }
                        try {
                            synchronized (this) {
                                //使用微信的提供有效时间 经常出现问题 现在定死为5分钟获取一次
                                this.wait(expiresIn * 1000);
                            }
                        } catch (InterruptedException ex) {
                            ex.printStackTrace();
                        }
                    }
                }
            };
            jsapitThread.start();
        }
    }

    public boolean messageReceive(HttpServletRequest request, HttpServletResponse response) throws UnsupportedEncodingException, IOException, Exception {
        InputStream is = request.getInputStream();
        InputStreamReader isr = new InputStreamReader(is, "UTF-8");
        OutputStream os = response.getOutputStream();
        boolean fromWeiXIn = false;
        StringBuilder sb = new StringBuilder();
        BufferedReader br = new BufferedReader(isr);
        String s = "";
        while ((s = br.readLine()) != null) {
            sb.append(s);
        }
        br.close();
        isr.close();
        is.close();
        String signature = request.getParameter("signature");
        String timestamp = request.getParameter("timestamp");
        String nonce = request.getParameter("nonce");
        String echostr = request.getParameter("echostr");
        SendMessageWrap wrap = null;
        if (WeiXinUtil.checkSignature(signature, timestamp, nonce, TOKEN)) {
            fromWeiXIn = true;
            if (echostr == null) {
                //这个是交互过程
                try {
                    wrap = this.messageConvert.preConvert(sb.toString(), echostr);
                    if (wrap != null && wrap.getBsm() != null) {
//                        os.write(bsm.toWeiXinMessageXMLString().getBytes("UTF-8"));
                        os.write(wrap.getBsm().toWeiXinMessageXMLString().getBytes("UTF-8"));
                    } else {
                        os.write("".getBytes());
                    }
                } catch (JDOMException ex) {
                    os.write("".getBytes());
                    throw new Exception("微信传入数据格式异常，不是一个有效的xml。");
                } catch (IOException ex) {
                    ex.printStackTrace();
                    os.write("".getBytes());
                }
            } else {
                //这个是首次接入的时候 的验证 需要将echostr 原样返回
                os.write(echostr.getBytes());
            }
        }
        os.flush();
        os.close();
        if (wrap != null && wrap.getMsc() != null) {
            wrap.getMsc().messageSent();
        }
        return fromWeiXIn;
    }

    /**
     * 取到就正常运行 取不到就抛异常
     *
     * @return
     * @throws Exception
     */
    private JsonNode getAccessTokenJson() throws WeixinMessageException {
        StringBuilder url = new StringBuilder();
        url.append("https://api.weixin.qq.com/cgi-bin/token?");
        url.append("grant_type=client_credential");
        url.append("&appid=").append(APPID);
        url.append("&secret=").append(APPSECRET);
        String jsonStr = WeiXinUtil.getHttpBackDomStr(url.toString());
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true);
        JsonNode jsono = null;
        try {
            jsono = objectMapper.readTree(jsonStr);
            if (jsono.has("errcode")) {
                Integer errcode = jsono.get("errcode").getIntValue();
                throw new WeixinMessageException(errcode);
            }
        } catch (IOException ex) {
            Logger.getLogger(WeiXinPublic.class.getName()).log(Level.SEVERE, null, ex);
        }
        return jsono;
    }

    private JsonNode getJsapiTicketJson() throws Exception {
        StringBuilder url = new StringBuilder();
        url.append("https://api.weixin.qq.com/cgi-bin/ticket/getticket?");
        url.append("access_token=").append(this.getAccessTokenFromCache());
        url.append("&type=jsapi");
        String jsonStr = WeiXinUtil.getHttpBackDomStr(url.toString());
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true);
        JsonNode jsono = objectMapper.readTree(jsonStr);
        String accessToken = jsono.get("ticket").getTextValue();
        if (accessToken == null) {
            throw new Exception(jsonStr);
        }
        return jsono;
    }

    public String getAccessTokenRealTime() throws Exception {
        JsonNode jsono = getAccessTokenJson();
        return jsono.get("access_token").getTextValue();
    }

    public String getAccessTokenFromCache() {
        if (this.atc == null || this.atc.getCache() == null || this.atc.getCache().expiresTime <= System.currentTimeMillis()) {
            return null;
        } else {
            return this.atc.getCache().accessToken;
        }
    }

    public String getJSAPITicketFromCaahe() {
        if (this.ticketCache == null || this.ticketCache.getCache() == null || this.ticketCache.getCache().expiresTime <= System.currentTimeMillis()) {
            return null;
        } else {
            return this.ticketCache.getCache().ticket;
        }
    }

    public WeiXinUserEntity getUser(String openId) throws WeixinMessageException {
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true);
        String infoUrl = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=%s&openid=%s&lang=zh_CN";
        WeiXinUserEntity weiXinUserEntity = new WeiXinUserEntity();
        try {
            //为关注用户数量
            JsonNode ifjson = objectMapper.readTree(getHttpBackDomStr(String.format(infoUrl, getAccessTokenFromCache(), openId)));
            if (ifjson.has("errcode") && ifjson.get("errcode").getIntValue() > 0) {
                throw new WeixinMessageException(ifjson.get("errcode").getIntValue());
            }
            if (ifjson.get("subscribe") != null) {
                weiXinUserEntity.setSubscribe(ifjson.get("subscribe").getValueAsInt());
            }
            if (ifjson.get("sex") != null) {
                weiXinUserEntity.setSex(ifjson.get("sex").getValueAsInt());
            }
            if (ifjson.get("openid") != null) {
                weiXinUserEntity.setOpenid(ifjson.get("openid").getValueAsText());
            }
            if (ifjson.get("nickname") != null) {
                weiXinUserEntity.setNickname(ifjson.get("nickname").getValueAsText());
            }
            if (ifjson.get("language") != null) {
                weiXinUserEntity.setLanguage(ifjson.get("language").getValueAsText());
            }
            if (ifjson.get("city") != null) {
                weiXinUserEntity.setCity(ifjson.get("city").getValueAsText());
            }
            if (ifjson.get("province") != null) {
                weiXinUserEntity.setProvince(ifjson.get("province").getValueAsText());
            }
            if (ifjson.get("country") != null) {
                weiXinUserEntity.setCountry(ifjson.get("country").getValueAsText());
            }
            if (ifjson.get("headimgurl") != null) {
                weiXinUserEntity.setHeadimgurl(ifjson.get("headimgurl").getValueAsText());
            }

            if (ifjson.get("subscribe_time") != null) {
                weiXinUserEntity.setSubscribeTime(new Date(ifjson.get("subscribe_time").getLongValue()));
            }
            if (ifjson.has("unionid")) {
                weiXinUserEntity.setUnionid(ifjson.get("unionid").getValueAsText());
            }

            if (ifjson.get("remark") != null) {
                weiXinUserEntity.setRemark(ifjson.get("remark").getValueAsText());
            }
            if (ifjson.get("groupid") != null) {
                weiXinUserEntity.setGroupid(ifjson.get("groupid").getValueAsInt());
            }

        } catch (IOException ex) {
            ex.printStackTrace();
        }
        return weiXinUserEntity;
    }

    /**
     * 上传图文消息内的图片获取URL
     * 请注意，本接口所上传的图片不占用公众号的素材库中图片数量的5000个的限制。图片仅支持jpg/png格式，大小必须在1MB以下。
     *
     * @param inputStream
     * @param fileName
     * @return
     */
    public String uploadImg(InputStream inputStream, String fileName) {
        StringBuilder sb = new StringBuilder();
        String[] fileNameSp = fileName.split("\\.");
        if (fileNameSp.length < 2) {
            return null;
        }
        String urlStr = "https://api.weixin.qq.com/cgi-bin/media/uploadimg?access_token=" + this.getAccessTokenFromCache();
        String BOUNDARY = "----------" + System.currentTimeMillis();

        // 请求正文信息  
        // 第一部分：  
        StringBuilder boundary = new StringBuilder();
        boundary.append("--"); // 必须多两道线  
        boundary.append(BOUNDARY);
        boundary.append("\r\n");
        boundary.append("Content-Disposition: form-data;name=\"file\";filename=\"").append(fileName).append("\"\r\n");
        boundary.append("Content-Type:application/octet-stream\r\n\r\n");
        try {
            URL url = new URL(urlStr);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("POST");
            conn.setConnectTimeout(10000);// 设置连接主机超时（单位：毫秒）
            conn.setReadTimeout(10000);// 设置从主机读取数据超时（单位：毫秒）
            conn.setDoOutput(true);
            conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + BOUNDARY);
            conn.setUseCaches(false); // post方式不能使用缓存  
            // 设置请求头信息  
            conn.setRequestProperty("Connection", "Keep-Alive");
            conn.setRequestProperty("Charset", "UTF-8");
            conn.connect();
            OutputStream os = conn.getOutputStream();

            byte[] b = new byte[1024 * 1024];
            os.write(boundary.toString().getBytes("utf-8"));
            while (true) {
                int read = inputStream.read(b);
                //判断是不是读到了数据流的末尾 ，防止出现死循环。  
                if (read == -1) {
                    break;
                }
                os.write(b);
            }
            os.write(("\r\n--" + BOUNDARY + "--\r\n").getBytes("utf-8"));
            inputStream.close();
            os.close();
            BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"));
            String str;
            while ((str = br.readLine()) != null) {
                sb.append(str);
            }
            br.close();
            conn.disconnect();
            ObjectMapper objectMapper = new ObjectMapper();
            JsonNode ifjson = objectMapper.readTree(sb.toString());
            if (ifjson.get("url") != null) {
                String imgUrl = ifjson.get("url").getTextValue();
                return imgUrl;
            }
        } catch (MalformedURLException ex) {
            ex.printStackTrace();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
        return null;
    }

    public boolean updateMenu(String enumJsonStr) {
        StringBuilder sb = new StringBuilder();
        try {
            String urlStr = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=" + this.getAccessTokenFromCache();
            URL url = new URL(urlStr);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("POST");
            conn.setConnectTimeout(10000);// 设置连接主机超时（单位：毫秒）
            conn.setReadTimeout(10000);// 设置从主机读取数据超时（单位：毫秒）
            conn.setDoOutput(true);
            OutputStream os = conn.getOutputStream();
            conn.connect();
            os.write(enumJsonStr.getBytes("utf-8"));
            os.close();
            BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"));
            String str;
            while ((str = br.readLine()) != null) {
                sb.append(str);
            }
            br.close();
            conn.disconnect();
            ObjectMapper objectMapper = new ObjectMapper();
            JsonNode ifjson = objectMapper.readTree(sb.toString());
            if (ifjson.get("errcode").getIntValue() == 0) {
                return true;
            }
        } catch (MalformedURLException ex) {
            ex.printStackTrace();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
        return false;
    }

    public static class AccessToken implements Serializable {

        /**
         * 凭证
         */
        private String accessToken;
        /**
         * 凭证时效
         */
        private int expiresIn;
        /**
         * 1970年开始的毫秒数 过期时间
         */
        private long expiresTime;

        public String getAccessToken() {
            return accessToken;
        }

        public int getExpiresIn() {
            return expiresIn;
        }

        public long getExpiresTime() {
            return expiresTime;
        }

    }

    public static class JSAPITicket implements Serializable {

        /**
         * 错误代码
         */
        private int errcode;
        /**
         * 错误描述
         */
        private String errmsg;
        /**
         * jsapi_ticket
         */
        private String ticket;
        /**
         * 凭证时效
         */
        private int expiresIn;
        /**
         * 过期时间
         */
        private long expiresTime;
    }

    /**
     * 通过上传的文件获得文件的media_id 供回复内容时使用 如果是视频素材 那么上床的时候请添加title 和 introduction 属性
     * 其他不需要添加这两个属性
     *
     * @param inputStream 文件输入流
     * @param filelength 文件长度
     * @param fileName 文件名
     * @param type 文件的类型 有 video image voice music .. 可进行拓展
     * @param title
     * @param introduction
     *
     * @return
     */
    public String uploadPermanentMaterial(
            InputStream inputStream, long filelength, String fileName, MaterialType type, String title, String introduction) throws WeixinMessageException {

        try {

            // 拼装请求地址
            String uploadMediaUrl = "http://api.weixin.qq.com/cgi-bin/material/add_material?access_token=" + this.getAccessTokenFromCache();
            URL url = new URL(uploadMediaUrl);
            String result = null;
//            String suffix = fileName.substring(fileName.lastIndexOf("."), fileName.length());
            HttpURLConnection con = (HttpURLConnection) url.openConnection();
            con.setRequestMethod("POST"); // 以Post方式提交表单，默认get方式
            con.setDoInput(true);
            con.setDoOutput(true);
            con.setUseCaches(false); // post方式不能使用缓存
            // 设置请求头信息
            con.setRequestProperty("Connection", "Keep-Alive");
            con.setRequestProperty("Charset", "UTF-8");

            // 设置边界,这里的boundary是http协议里面的分割符
            String BOUNDARY = "----------" + System.currentTimeMillis();
            con.setRequestProperty("Content-Type",
                    "multipart/form-data; boundary=" + BOUNDARY);
            // 请求正文信息
            // 第一部分：
            StringBuilder sb = new StringBuilder();
            if (type.equals(MaterialType.VIDEO)) {
                ObjectNode json = new ObjectNode(JsonNodeFactory.instance);
                json.put("title", title);
                json.put("introduction", introduction);
                sb.append("--").append(BOUNDARY); // 必须多两道线 http 协议头
                sb.append("\r\n");
                sb.append("Content-Disposition: form-data; name=\"description\"");
                sb.append("\r\n");
                sb.append("\r\n");
                sb.append(json.toString());
            }
            //这块是post提交type的值也就是文件对应的类型值
            sb.append("--").append(BOUNDARY); // 必须多两道线 http 协议头
            sb.append("\r\n");
            sb.append("Content-Disposition: form-data;name=\"type\" \r\n\r\n"); //这里是参数名，参数名和值之间要用两次
            sb.append(type.getValue()).append("\r\n"); //参数的值
            sb.append("--"); // 必须多两道线
            sb.append(BOUNDARY);
            sb.append("\r\n");
            //这里是media参数相关的信息
            sb.append("Content-Disposition: form-data;name=\"media\";filename=\"").append(fileName).append("\";filelength=\"").append(filelength).append("\" \r\n");
            sb.append("Content-Type:application/octet-stream\r\n\r\n");
            byte[] head = sb.toString().getBytes("utf-8");
            // 获得输出流
            OutputStream out = new DataOutputStream(con.getOutputStream());
            // 输出表头
            out.write(head);
            // 文件正文部分
            // 把文件已流文件的方式 推入到url中

            int bytes = 0;
            byte[] bufferOut = new byte[1024];
            while ((bytes = inputStream.read(bufferOut)) != -1) {
                out.write(bufferOut, 0, bytes);
            }
            inputStream.close();
            // 结尾部分，这里结尾表示整体的参数的结尾，结尾要用"--"作为结束，这些都是http协议的规定
            byte[] foot = ("\r\n--" + BOUNDARY + "--\r\n").getBytes("utf-8");// 定义最后数据分隔线
            out.write(foot);
            out.flush();
            out.close();
            StringBuilder buffer = new StringBuilder();
            BufferedReader reader = null;
            // 定义BufferedReader输入流来读取URL的响应
            reader = new BufferedReader(new InputStreamReader(
                    con.getInputStream(), "utf-8"));
            String line = null;
            while ((line = reader.readLine()) != null) {
                buffer.append(line);
            }
            if (result == null) {
                result = buffer.toString();
            }
            ObjectMapper objectMapper = new ObjectMapper();
            // 使用JSONNode解析返回结果
            JsonNode ifjson = objectMapper.readTree(result);
            //直接返回获取到的数据，在页面上进行将返回值赋值
            if (ifjson.has("errcode")) {
                throw new WeixinMessageException(ifjson.get("errcode").getIntValue());
            }
            return ifjson.toString();
//			if (ifjson.has("media_id")) {
//				String media_id = ifjson.get("media_id").getTextValue();
//			} else {
//			}

        } catch (IOException e) {
            e.printStackTrace();
        } finally {

        }
        return "";
    }

    /**
     * 获取当前公众号菜单的内容，方便编辑查看
     *
     * @return
     */
    public String getMenu() {
        StringBuilder sb = new StringBuilder();
        try {
            String urlStr = "https://api.weixin.qq.com/cgi-bin/get_current_selfmenu_info?access_token=" + this.getAccessTokenFromCache();
            URL url = new URL(urlStr);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("POST");
            conn.setConnectTimeout(10000);// 设置连接主机超时（单位：毫秒）
            conn.setReadTimeout(10000);// 设置从主机读取数据超时（单位：毫秒）
            conn.setDoOutput(true);
            OutputStream os = conn.getOutputStream();
            conn.connect();
            os.close();
            BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"));
            String str;
            while ((str = br.readLine()) != null) {
                sb.append(str);
            }
            br.close();
            conn.disconnect();
            ObjectMapper objectMapper = new ObjectMapper();
            JsonNode ifjson = objectMapper.readTree(sb.toString());
            if (ifjson.has("is_menu_open")) {
                if (ifjson.get("is_menu_open").getIntValue() == 0) {

                    return "";
                } else {
                    JsonNode beg = ifjson.get("selfmenu_info");
                    JsonNode begin = beg.get("button");
                    for (int i = 0; i < begin.size(); i++) {
                        if (begin.get(i).has("sub_button")) {
                            JsonNode subBut = begin.get(i).path("sub_button");
                            String list = subBut.get("list").toString();
                            if (!subBut.toString().equalsIgnoreCase(list)) {

                                ((ObjectNode) begin.get(i)).put("sub_button", "%" + list + "%");
                            }

                        }

                    }
                    String menu = beg.toString();
                    String menuStr = StringEscapeUtils.unescapeJava(menu);
                    int[] arr = this.count(menuStr, '%');
//                 	menuStr = menuStr.substring(0, arr[0]-1) + menuStr.substring(arr[0] + 1, arr[1]) + menuStr.substring(arr[1] + 2,arr[2] - 1) + 
//                 			menuStr.substring(arr[2] + 1,arr[3]) + menuStr.substring(arr[3] + 2, menuStr.length());
                    StringBuilder sb1 = new StringBuilder();
                    sb1.append(menuStr.substring(0, arr[0] - 1));
                    for (int i = 0; i < arr.length - 1; i++) {
                        if (i % 2 == 0) {
                            sb1.append(menuStr.substring(arr[i] + 1, arr[i + 1]));
                        } else {
                            sb1.append(menuStr.substring(arr[i] + 2, arr[i + 1] - 1));
                        }

                    }
                    sb1.append(menuStr.substring(arr[arr.length - 1] + 2, menuStr.length()));
                    return sb1.toString();
                }
            }

        } catch (MalformedURLException ex) {
            ex.printStackTrace();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
        return "";
    }

    public static int[] count(String str, char key) {
        int[] count = {};
        for (int i = 0; i < str.length(); i++) {
            char c = str.charAt(i);
            if (c == key) {
                // 扩展数组,
                count = Arrays.copyOf(count, count.length + 1);
                // 添加序号 i
                count[count.length - 1] = i;
            }
        }
        return count;
    }

    /**
     * 用户列表对象
     *
     */
    public static class BatchOpenIdObject implements Serializable {

        private int total;
        private int count;
        private List<String> list;
        private String nextOpenid;

        public int getTotal() {
            return total;
        }

        public void setTotal(int total) {
            this.total = total;
        }

        public int getCount() {
            return count;
        }

        public void setCount(int count) {
            this.count = count;
        }

        public List<String> getList() {
            return list;
        }

        public void setList(List<String> list) {
            this.list = list;
        }

        public String getNextOpenid() {
            return nextOpenid;
        }

        public void setNextOpenid(String nextOpenid) {
            this.nextOpenid = nextOpenid;
        }

    }
//    /**
//     * 获取模板列表
//     */

    public String getTempList() {

        String urlStr = "https://api.weixin.qq.com/cgi-bin/template/get_all_private_template?access_token=" + this.getAccessTokenFromCache();
        String resultStr = this.sendGet(urlStr);
        return resultStr;
    }

    /**
     * 模板消息推送
     *
     * @param openId
     * @param templateId
     * @param url
     * @param dataList
     * @return
     */
    public boolean templteMessage(String openId, String templateId, String url, List<TemplateData> dataList) {
        ObjectNode jsono = new ObjectNode(JsonNodeFactory.instance);
        jsono.put("touser", openId);
        jsono.put("template_id", templateId);
        jsono.put("url", url);
        ObjectNode jsona = new ObjectNode(JsonNodeFactory.instance);
        if (dataList != null && !dataList.isEmpty()) {
            for (TemplateData templateData : dataList) {
                ObjectNode jdata = new ObjectNode(JsonNodeFactory.instance);
                jdata.put("value", templateData.getValue());
                jdata.put("color", templateData.getColor());
                jsona.put(templateData.getKey(), jdata);
            }
        }
        jsono.put("data", jsona);
        StringBuilder sb = new StringBuilder();
        try {
            String urlStr = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=" + this.getAccessTokenFromCache();
            URL url1 = new URL(urlStr);
            HttpURLConnection conn = (HttpURLConnection) url1.openConnection();
            conn.setRequestMethod("POST");
            conn.setConnectTimeout(10000);// 设置连接主机超时（单位：毫秒）
            conn.setReadTimeout(10000);// 设置从主机读取数据超时（单位：毫秒）
            conn.setDoOutput(true);
            OutputStream os = conn.getOutputStream();
            conn.connect();
            os.write(jsono.toString().getBytes("utf-8"));
            os.close();
            BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"));
            String str;
            while ((str = br.readLine()) != null) {
                sb.append(str);
            }
            br.close();
            conn.disconnect();
            ObjectMapper objectMapper = new ObjectMapper();
            JsonNode ifjson = objectMapper.readTree(sb.toString());
            int valueAsInt = ifjson.get("errcode").getValueAsInt();
            if (valueAsInt == 0) {
                return true;
            } else {
                return false;
            }
        } catch (MalformedURLException ex) {
            ex.printStackTrace();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
        return false;
    }

    /**
     * 获取用户列表 当返回数据中 next_openid 为空字符串时表示获取列表完毕，返回结果封装为一个对象
     *
     * @param requestUrl
     * @return
     */
    public BatchOpenIdObject getBatchOpenIdObject(String nextOpenId) throws WeixinMessageException {
        BatchOpenIdObject ul = new BatchOpenIdObject();
        List<String> list = new ArrayList<String>();
        String urlStr = "https://api.weixin.qq.com/cgi-bin/user/get?access_token=" + this.getAccessTokenFromCache() + "&next_openid=" + nextOpenId;
        String resultStr = this.sendGet(urlStr);
        try {
            ObjectMapper objectMapper = new ObjectMapper();
            JsonNode ifjson = objectMapper.readTree(resultStr.toString());
            if (ifjson.has("total") && ifjson.has("count")) {
                ul.setCount(ifjson.get("total").getValueAsInt());
                ul.setNextOpenid(ifjson.get("next_openid").getTextValue());
                ul.setTotal(ifjson.get("total").getValueAsInt());
                if (ifjson.has("data")) {
                    for (int i = 0; i < ifjson.get("data").get("openid").size(); i++) {
                        list.add(ifjson.get("data").get("openid").get(i).getTextValue());
                        ul.setList(list);
                    }
                } else if (ifjson.has("errcode")) {
                    throw new WeixinMessageException(ifjson.get("errcode").getIntValue());
                }
            }
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return ul;
    }

    //get请求不带参数的方法
    public static String sendGet(String requestUrl) {
        StringBuilder sb = new StringBuilder();
        JsonNode ifjson = null;
        try {
            // 建立连接
            URL url = new URL(requestUrl);
            HttpURLConnection httpUrlConn = (HttpURLConnection) url.openConnection();
            httpUrlConn.setDoInput(true);
            httpUrlConn.setRequestMethod("GET");

            // 获取输入流
            InputStream inputStream = httpUrlConn.getInputStream();
            InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
            BufferedReader bufferedReader = new BufferedReader(inputStreamReader);

            // 读取返回结果
            String str = null;
            while ((str = bufferedReader.readLine()) != null) {
                sb.append(str);
            }

            // 释放资源
            bufferedReader.close();
            inputStreamReader.close();
            inputStream.close();
            httpUrlConn.disconnect();
            ObjectMapper objectMapper = new ObjectMapper();
            ifjson = objectMapper.readTree(sb.toString());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return ifjson.toString();
    }

    /**
     * 创建代参二维码接口
     *
     * @param qp
     * @return
     */
    public QrcodeEntity createQrcode(QrcodeParameter qp) {
        StringBuilder sb = new StringBuilder();
        ObjectNode paraJson = new ObjectNode(JsonNodeFactory.instance);
        paraJson.put("action_name", qp.getActionName().getValue());
        switch (qp.getActionName()) {
            case QR_SCENE: {
                paraJson.put("expire_seconds", qp.getExpireSeconds());
                ObjectNode sceneId = new ObjectNode(JsonNodeFactory.instance);
                sceneId.put("scene_id", qp.getSceneId());
                ObjectNode scene = new ObjectNode(JsonNodeFactory.instance);
                scene.put("scene", sceneId);
                paraJson.put("action_info", scene);
            }
            break;
            case QR_LIMIT_SCENE: {
                ObjectNode sceneId = new ObjectNode(JsonNodeFactory.instance);
                sceneId.put("scene_id", qp.getSceneId());
                ObjectNode scene = new ObjectNode(JsonNodeFactory.instance);
                scene.put("scene", sceneId);
                paraJson.put("action_info", scene);
            }
            break;
            case QR_LIMIT_STR_SCENE: {
                ObjectNode sceneStr = new ObjectNode(JsonNodeFactory.instance);
                sceneStr.put("scene_str", qp.getSceneId());
                ObjectNode scene = new ObjectNode(JsonNodeFactory.instance);
                scene.put("scene", sceneStr);
                paraJson.put("action_info", scene);
            }
        }
        try {
            String urlStr = "https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=" + this.getAccessTokenFromCache();
            URL url1 = new URL(urlStr);
            HttpURLConnection conn = (HttpURLConnection) url1.openConnection();
            conn.setRequestMethod("POST");
            conn.setConnectTimeout(10000);// 设置连接主机超时（单位：毫秒）
            conn.setReadTimeout(10000);// 设置从主机读取数据超时（单位：毫秒）
            conn.setDoOutput(true);
            OutputStream os = conn.getOutputStream();
            conn.connect();
            os.write(paraJson.toString().getBytes("utf-8"));
            os.close();
            BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"));
            String str;
            while ((str = br.readLine()) != null) {
                sb.append(str);
            }
            br.close();
            conn.disconnect();
            ObjectMapper objectMapper = new ObjectMapper();
            JsonNode ifjson = objectMapper.readTree(sb.toString());
            JsonNode errcodeJson = ifjson.get("errcode");
            if (errcodeJson == null) {
                QrcodeEntity qe = new QrcodeEntity();
                JsonNode expireSecondsJson = ifjson.get("expire_seconds");
                if (expireSecondsJson != null) {
                    qe.setExpireSeconds(ifjson.get("expire_seconds").getIntValue());
                } else {
                    qe.setExpireSeconds(-1);
                }
                qe.setTicket(ifjson.get("ticket").getTextValue());
                qe.setUrl(ifjson.get("url").getTextValue());
                return qe;
            } else {
                return null;
            }
        } catch (MalformedURLException ex) {
            return null;
        } catch (IOException ex) {
            return null;
        }
    }

    public String groupMessage(int groupId) {
        String jsonStr = "{\"filter\":{\"is_to_all\":false,\"group_id\":\"" + groupId + "\"},\"mpnews\":{\"media_id\":\"JKTryU2nK8A528phUlC0AXD37PnN3v0blAMPd3ih0sA\"},\"msgtype\":\"mpnews\"}";
        StringBuilder sb = new StringBuilder();
        try {
            String urlStr = "https://api.weixin.qq.com/cgi-bin/message/mass/sendall?access_token=" + this.getAccessTokenFromCache();
            URL url1 = new URL(urlStr);
            HttpURLConnection conn = (HttpURLConnection) url1.openConnection();
            conn.setRequestMethod("POST");
            conn.setConnectTimeout(10000);// 设置连接主机超时（单位：毫秒）
            conn.setReadTimeout(10000);// 设置从主机读取数据超时（单位：毫秒）
            conn.setDoOutput(true);
            OutputStream os = conn.getOutputStream();
            conn.connect();
            os.write(jsonStr.getBytes("utf-8"));
            os.close();
            BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"));
            String str;
            while ((str = br.readLine()) != null) {
                sb.append(str);
            }
            br.close();
        } catch (MalformedURLException ex) {
            Logger.getLogger(WeiXinPublic.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(WeiXinPublic.class.getName()).log(Level.SEVERE, null, ex);
        }
        return sb.toString();
    }

    public List<GroupEntity> getAllGroup() {
        StringBuilder sb = new StringBuilder();
        List<GroupEntity> ges = new LinkedList<GroupEntity>();
        try {
            String apiUrl = "https://api.weixin.qq.com/cgi-bin/groups/get?access_token=" + this.getAccessTokenFromCache();
            URL url1 = new URL(apiUrl);
            HttpURLConnection conn = (HttpURLConnection) url1.openConnection();
            conn.setRequestMethod("POST");
            conn.setConnectTimeout(10000);// 设置连接主机超时（单位：毫秒）
            conn.setReadTimeout(10000);// 设置从主机读取数据超时（单位：毫秒）
            conn.setDoOutput(true);
            conn.connect();
            BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"));
            String str;
            while ((str = br.readLine()) != null) {
                sb.append(str);
            }
            br.close();
            ObjectMapper objectMapper = new ObjectMapper();
            JsonNode ifjson = objectMapper.readTree(sb.toString());
            if (ifjson.has("groups")) {
                JsonNode groups = ifjson.get("groups");
                for (JsonNode group : groups) {
                    GroupEntity ge = new GroupEntity();
                    ge.setCount(group.get("count").getIntValue());
                    ge.setId(group.get("id").getIntValue());
                    ge.setName(group.get("name").getTextValue());
                    ges.add(ge);
                }
            }
        } catch (MalformedURLException ex) {
            ex.printStackTrace();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
        return ges;
    }

    public String createKeFu(String account, String nickname, String password) {
        try {
            String url = "https://api.weixin.qq.com/customservice/kfaccount/add?access_token=" + this.getAccessTokenFromCache();
            ObjectNode json = new ObjectNode(JsonNodeFactory.instance);
            json.put("kf_account", account);
            json.put("nickname", nickname);
            json.put("password", MD5.MD5(password));
            StringBuilder sb = new StringBuilder();
            URL url1 = new URL(url);
            HttpURLConnection conn = (HttpURLConnection) url1.openConnection();
            conn.setRequestMethod("POST");
            conn.setConnectTimeout(10000);// 设置连接主机超时（单位：毫秒）
            conn.setReadTimeout(10000);// 设置从主机读取数据超时（单位：毫秒）
            conn.setDoOutput(true);
            OutputStream os = conn.getOutputStream();
            conn.connect();
            os.write(json.toString().getBytes("utf-8"));
            os.close();
            BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"));
            String str;
            while ((str = br.readLine()) != null) {
                sb.append(str);
            }
            br.close();
            return sb.toString();
        } catch (MalformedURLException ex) {
            Logger.getLogger(WeiXinPublic.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(WeiXinPublic.class.getName()).log(Level.SEVERE, null, ex);
        }
        return null;
    }

    public String updateKeFu(String account, String nickname, String password) {
        try {
            String url = "https://api.weixin.qq.com/customservice/kfaccount/update?access_token=" + this.getAccessTokenFromCache();
            ObjectNode json = new ObjectNode(JsonNodeFactory.instance);
            json.put("kf_account", account);
            json.put("nickname", nickname);
            json.put("password", MD5.MD5(password));
            StringBuilder sb = new StringBuilder();
            URL url1 = new URL(url);
            HttpURLConnection conn = (HttpURLConnection) url1.openConnection();
            conn.setRequestMethod("POST");
            conn.setConnectTimeout(10000);// 设置连接主机超时（单位：毫秒）
            conn.setReadTimeout(10000);// 设置从主机读取数据超时（单位：毫秒）
            conn.setDoOutput(true);
            OutputStream os = conn.getOutputStream();
            conn.connect();
            os.write(json.toString().getBytes("utf-8"));
            os.close();
            BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"));
            String str;
            while ((str = br.readLine()) != null) {
                sb.append(str);
            }
            br.close();
            return sb.toString();
        } catch (MalformedURLException ex) {
            Logger.getLogger(WeiXinPublic.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(WeiXinPublic.class.getName()).log(Level.SEVERE, null, ex);
        }
        return null;

    }

    public String deleteKeFu(String account) {
        try {
            String url = "https://api.weixin.qq.com/customservice/kfaccount/del?access_token=" + this.getAccessTokenFromCache() + "&kf_account=" + account;
            /* String url = "https://api.weixin.qq.com/customservice/kfaccount/del?access_token=" + this.getAccessTokenFromCache();
            JSONObject json = new JSONObject();
            json.put("kf_account", account);
            json.put("nickname", nickname);
            json.put("password", MD5.MD5(password));*/
            StringBuilder sb = new StringBuilder();
            URL url1 = new URL(url);
            HttpURLConnection conn = (HttpURLConnection) url1.openConnection();
            conn.setRequestMethod("GET");
            conn.setConnectTimeout(10000);// 设置连接主机超时（单位：毫秒）
            conn.setReadTimeout(10000);// 设置从主机读取数据超时（单位：毫秒）
            conn.setDoOutput(true);
            conn.connect();
            BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"));
            String str;
            while ((str = br.readLine()) != null) {
                sb.append(str);
            }
            br.close();
            return sb.toString();
        } catch (MalformedURLException ex) {
            Logger.getLogger(WeiXinPublic.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(WeiXinPublic.class.getName()).log(Level.SEVERE, null, ex);
        }
        return null;

    }

    /**
     *
     * @param online true 仅仅在线的客服 false 全部客服
     * @return
     * @throws WeixinMessageException
     */
    public List<WeiXinKeFuUser> getKeFuList(boolean online) throws WeixinMessageException {
        try {
            String url = null;
            if (online) {
                url = "https://api.weixin.qq.com/cgi-bin/customservice/getonlinekflist?access_token=" + this.getAccessTokenFromCache();
            } else {
                url = "https://api.weixin.qq.com/cgi-bin/customservice/getkflist?access_token=" + this.getAccessTokenFromCache();
            }
            StringBuilder sb = new StringBuilder();
            URL url1 = new URL(url);
            HttpURLConnection conn = (HttpURLConnection) url1.openConnection();
            conn.setRequestMethod("POST");
            conn.setConnectTimeout(10000);// 设置连接主机超时（单位：毫秒）
            conn.setReadTimeout(10000);// 设置从主机读取数据超时（单位：毫秒）
            conn.setDoOutput(true);
            conn.connect();
            BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"));
            String str;
            while ((str = br.readLine()) != null) {
                sb.append(str);
            }
            br.close();
            System.err.println(sb);
            ObjectMapper objectMapper = new ObjectMapper();
            JsonNode ifjson = objectMapper.readTree(sb.toString());
            List<WeiXinKeFuUser> weiXinKeFuUsers = new LinkedList<WeiXinKeFuUser>();
            if (ifjson.has("kf_list")) {
                JsonNode kefuList = ifjson.get("kf_list");
                for (JsonNode group : kefuList) {
                    WeiXinKeFuUser wxkfu = new WeiXinKeFuUser();
                    wxkfu.setKfAccount(group.findValue("kf_account").getTextValue());
                    wxkfu.setKfHeadimgurl(group.findValue("kf_headimgurl").getTextValue());
                    wxkfu.setKfId(group.findValue("kf_id").getTextValue());
                    wxkfu.setKfNick(group.findValue("kf_nick").getTextValue());
                    weiXinKeFuUsers.add(wxkfu);
                }
            } else if (ifjson.has("errcode")) {
                throw new WeixinMessageException(ifjson.get("errcode").getIntValue());
            }
            return weiXinKeFuUsers;
        } catch (MalformedURLException ex) {
            ex.printStackTrace();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
        return null;
    }

    /**
     * 设置客服头像
     *
     * @param inputStream
     * @param fileName
     * @param kefuAccount
     * @throws com.motie.wings.utils.weixin.WXpublic.WeixinMessageException
     */
    public void uploadKeFuHeadimg(InputStream inputStream, String fileName, String kefuAccount) throws WeixinMessageException {

        try {
            StringBuilder sb = new StringBuilder();
            String[] fileNameSp = fileName.split("\\.");
            if (fileNameSp.length < 2) {
                return;
            }
            String uploadMediaUrl = "http://api.weixin.qq.com/customservice/kfaccount/uploadheadimg?access_token=" + this.getAccessTokenFromCache() + "&kf_account=" + kefuAccount;
            String BOUNDARY = "----------" + System.currentTimeMillis();
            // 拼装请求地址
            StringBuilder boundary = new StringBuilder();
            boundary.append("--"); // 必须多两道线  
            boundary.append(BOUNDARY);
            boundary.append("\r\n");
            boundary.append("Content-Disposition: form-data;name=\"media\";filename=\"").append(fileName).append("\"\r\n");
            boundary.append("Content-Type:image/jpeg\r\n\r\n");

            URL url = new URL(uploadMediaUrl);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("POST");
            conn.setConnectTimeout(10000);// 设置连接主机超时（单位：毫秒）
            conn.setReadTimeout(10000);// 设置从主机读取数据超时（单位：毫秒）
            conn.setDoOutput(true);
            conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + BOUNDARY);
            conn.setUseCaches(false); // post方式不能使用缓存  
            // 设置请求头信息  
            conn.setRequestProperty("Connection", "Keep-Alive");
            conn.setRequestProperty("Charset", "UTF-8");
            conn.connect();
            OutputStream os = conn.getOutputStream();

            byte[] b = new byte[1024 * 1024];
            os.write(boundary.toString().getBytes("utf-8"));
            while (true) {
                int read = inputStream.read(b);
                //判断是不是读到了数据流的末尾 ，防止出现死循环。  
                if (read == -1) {
                    break;
                }
                os.write(b);
            }
            os.write(("\r\n--" + BOUNDARY + "--\r\n").getBytes("utf-8"));
            inputStream.close();
            os.close();
            BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"));
            String str;
            while ((str = br.readLine()) != null) {
                sb.append(str);
            }
            br.close();
            conn.disconnect();
            ObjectMapper objectMapper = new ObjectMapper();
            JsonNode ifjson = objectMapper.readTree(sb.toString());
            if (ifjson.has("errcode")) {
                throw new WeixinMessageException(ifjson.get("errcode").getIntValue());
            }
        } catch (MalformedURLException ex) {
            System.out.println(ex);
            ex.printStackTrace();
        } catch (IOException ex) {
            System.out.println(ex);
            ex.printStackTrace();
        }
    }

    /**
     * 发送客服消息 如果不设定客服账号的话 那么就使用默认客服 如果添加了客服账号 那就使用指定的客服账号发送
     *
     * @param bskm
     * @return
     * @throws com.motie.wings.utils.weixin.WXpublic.WeixinMessageException
     */
    public void sendKefuMessage(BaseSendKefuMessage bskm) throws WeixinMessageException {
        try {
            String url = "https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=" + this.getAccessTokenFromCache();
            StringBuilder sb = new StringBuilder();
            URL url1 = new URL(url);
            HttpURLConnection conn = (HttpURLConnection) url1.openConnection();
            conn.setRequestMethod("POST");
            conn.setConnectTimeout(10000);// 设置连接主机超时（单位：毫秒）
            conn.setReadTimeout(10000);// 设置从主机读取数据超时（单位：毫秒）
            conn.setDoOutput(true);
            conn.connect();
            OutputStream os = conn.getOutputStream();
            os.write(bskm.toWeiXinKefuMessageJsonString().getBytes("utf-8"));
            os.close();
            BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"));
            String str;
            while ((str = br.readLine()) != null) {
                sb.append(str);
            }
            br.close();
            ObjectMapper objectMapper = new ObjectMapper();
            JsonNode ifjson = objectMapper.readTree(sb.toString());
            if (ifjson.has("errcode") && ifjson.get("errcode").getIntValue() != 0) {
                throw new WeixinMessageException(ifjson.get("errcode").getIntValue());
            }
        } catch (MalformedURLException ex) {
            Logger.getLogger(WeiXinPublic.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(WeiXinPublic.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    /**
     * 手动关闭客服会话的方法
     *
     * @param openid 用户的openId
     * @param kfAccount 客服的账号
     * @param text 当会话关闭后 出现在客服客户端上的一串提示语
     * @throws WeixinMessageException
     */
    public void closeKefuSession(String openid, String kfAccount, String text) throws WeixinMessageException {
        try {
            ObjectNode json = new ObjectNode(JsonNodeFactory.instance);
            json.put("kf_account", kfAccount);
            json.put("openid", openid);
            json.put("text", text);
            String url = " https://api.weixin.qq.com/customservice/kfsession/close?access_token=" + this.getAccessTokenFromCache();
            StringBuilder sb = new StringBuilder();
            URL url1 = new URL(url);
            HttpURLConnection conn = (HttpURLConnection) url1.openConnection();
            conn.setRequestMethod("POST");
            conn.setConnectTimeout(10000);// 设置连接主机超时（单位：毫秒）
            conn.setReadTimeout(10000);// 设置从主机读取数据超时（单位：毫秒）
            conn.setDoOutput(true);
            OutputStream os = conn.getOutputStream();
            conn.connect();
            os.write(json.toString().getBytes("utf-8"));
            os.close();
            BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"));
            String str;
            while ((str = br.readLine()) != null) {
                sb.append(str);
            }
            br.close();
            ObjectMapper objectMapper = new ObjectMapper();
            JsonNode ifjson = objectMapper.readTree(sb.toString());
            if (ifjson.has("errcode")) {
                throw new WeixinMessageException(ifjson.get("errcode").getIntValue());
            }
        } catch (MalformedURLException ex) {
            ex.printStackTrace();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }

    /**
     * 获取用户当前的客服会话状态
     *
     * @param opentId
     * @return
     * @throws WeixinMessageException
     */
    public SessionKefu getSessionForUser(String opentId) throws WeixinMessageException {
        SessionKefu sk = null;
        try {
            String url = "https://api.weixin.qq.com/customservice/kfsession/getsession?access_token=" + this.getAccessTokenFromCache() + "&openid=" + opentId;
            StringBuilder sb = new StringBuilder();
            URL url1 = new URL(url);
            HttpURLConnection conn = (HttpURLConnection) url1.openConnection();
            conn.setRequestMethod("POST");
            conn.setConnectTimeout(10000);// 设置连接主机超时（单位：毫秒）
            conn.setReadTimeout(10000);// 设置从主机读取数据超时（单位：毫秒）
            conn.setDoOutput(true);
            conn.connect();
            BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"));
            String str;
            while ((str = br.readLine()) != null) {
                sb.append(str);
            }
            br.close();
            ObjectMapper objectMapper = new ObjectMapper();
            JsonNode ifjson = objectMapper.readTree(sb.toString());
            if (ifjson.has("kf_account")) {
                sk = new SessionKefu();
                sk.setCreatetime(new Date(ifjson.get("createtime").getLongValue()));
                sk.setKfAccount(ifjson.get("kf_account").getTextValue());
            } else if (ifjson.has("errcode")) {
                throw new WeixinMessageException(ifjson.get("errcode").getIntValue());
            }
        } catch (MalformedURLException ex) {
            ex.printStackTrace();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
        return sk;
    }

    /**
     * 获取客服的会话列表
     *
     * @param kefuAccount
     * @return
     * @throws WeixinMessageException
     */
    public List<SessionUser> getKefuSessionList(String kefuAccount) throws WeixinMessageException {
        List<SessionUser> suList = null;
        try {
            String url = "https://api.weixin.qq.com/customservice/kfsession/getsessionlist?access_token=" + this.getAccessTokenFromCache() + "&kf_account=" + kefuAccount;
            StringBuilder sb = new StringBuilder();
            URL url1 = new URL(url);
            HttpURLConnection conn = (HttpURLConnection) url1.openConnection();
            conn.setRequestMethod("POST");
            conn.setConnectTimeout(10000);// 设置连接主机超时（单位：毫秒）
            conn.setReadTimeout(10000);// 设置从主机读取数据超时（单位：毫秒）
            conn.setDoOutput(true);
            conn.connect();
            BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"));
            String str;
            while ((str = br.readLine()) != null) {
                sb.append(str);
            }
            br.close();
            ObjectMapper objectMapper = new ObjectMapper();
            JsonNode ifjson = objectMapper.readTree(sb.toString());
            if (ifjson.has("sessionlist")) {
                suList = new LinkedList<SessionUser>();
                JsonNode get = ifjson.get("sessionlist");
                for (JsonNode jsonNode : get) {
                    SessionUser su = new SessionUser();
                    su.setCreatetime(new Date(jsonNode.get("createtime").getLongValue()));
                    su.setOpenid(jsonNode.get("openid").getTextValue());
                    suList.add(su);
                }
            } else if (ifjson.has("errcode")) {
                throw new WeixinMessageException(ifjson.get("errcode").getIntValue());
            }
        } catch (MalformedURLException ex) {
            ex.printStackTrace();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
        return suList;
    }

    /**
     * 获取客服的等待队列
     *
     * @param kefuAccount
     * @return
     * @throws WeixinMessageException
     */
    public WaitingSessionList getKefuWaitingSession(String kefuAccount) throws WeixinMessageException {
        WaitingSessionList suwList = null;
        try {
            String url = "https://api.weixin.qq.com/customservice/kfsession/getsessionlist?access_token=" + this.getAccessTokenFromCache() + "&kf_account=" + kefuAccount;
            StringBuilder sb = new StringBuilder();
            URL url1 = new URL(url);
            HttpURLConnection conn = (HttpURLConnection) url1.openConnection();
            conn.setRequestMethod("POST");
            conn.setConnectTimeout(10000);// 设置连接主机超时（单位：毫秒）
            conn.setReadTimeout(10000);// 设置从主机读取数据超时（单位：毫秒）
            conn.setDoOutput(true);
            conn.connect();
            BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"));
            String str;
            while ((str = br.readLine()) != null) {
                sb.append(str);
            }
            br.close();
            ObjectMapper objectMapper = new ObjectMapper();
            JsonNode ifjson = objectMapper.readTree(sb.toString());
            if (ifjson.has("waitcaselist")) {
                suwList = new WaitingSessionList();
                List<WaitingSession> suList = new LinkedList<WaitingSession>();
                JsonNode get = ifjson.get("waitcaselist");
                JsonNode count = ifjson.get("count");
                for (JsonNode jsonNode : get) {
                    WaitingSession su = new WaitingSession();
                    su.setCreatetime(new Date(jsonNode.get("createtime").getLongValue()));
                    su.setOpenid(jsonNode.get("openid").getTextValue());
                    su.setKfAccount(jsonNode.get("kf_account").getTextValue());
                    suList.add(su);
                }
                suwList.setCount(count.getIntValue());
                suwList.setWsList(suList);
            } else if (ifjson.has("errcode")) {
                throw new WeixinMessageException(ifjson.get("errcode").getIntValue());
            }
        } catch (MalformedURLException ex) {
            ex.printStackTrace();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
        return suwList;
    }

    /**
     * 根据时间条件 查询客服的消息记录
     *
     * @param starttime
     * @param endtime
     * @param pageindex
     * @param pagesize
     * @return
     * @throws WeixinMessageException
     */
    public KefuDialogList getKefuDialogList(Date starttime, Date endtime, int pageindex, int pagesize) throws WeixinMessageException {
        KefuDialogList kdl = null;
        try {
            ObjectNode json = new ObjectNode(JsonNodeFactory.instance);
            json.put("endtime", endtime.getTime());
            json.put("pageindex", pageindex);
            json.put("pagesize", pagesize);
            json.put("starttime", starttime.getTime());
            String url = "https://api.weixin.qq.com/customservice/msgrecord/getrecord?access_token=" + this.getAccessTokenFromCache();
            StringBuilder sb = new StringBuilder();
            URL url1 = new URL(url);
            HttpURLConnection conn = (HttpURLConnection) url1.openConnection();
            conn.setRequestMethod("POST");
            conn.setConnectTimeout(10000);// 设置连接主机超时（单位：毫秒）
            conn.setReadTimeout(10000);// 设置从主机读取数据超时（单位：毫秒）
            conn.setDoOutput(true);
            OutputStream os = conn.getOutputStream();
            conn.connect();
            os.write(json.toString().getBytes());
            BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"));
            String str;
            while ((str = br.readLine()) != null) {
                sb.append(str);
            }
            br.close();
            ObjectMapper objectMapper = new ObjectMapper();
            JsonNode ifjson = objectMapper.readTree(sb.toString());
            if (ifjson.has("waitcaselist")) {
                kdl = new KefuDialogList();
                List<KefuDialog> suList = new LinkedList<KefuDialog>();
                JsonNode get = ifjson.get("waitcaselist");
                for (JsonNode jsonNode : get) {
                    KefuDialog su = new KefuDialog();
                    su.setKefuAccount(jsonNode.get("worker").getTextValue());
                    su.setOpenid(jsonNode.get("openid").getTextValue());
                    su.setOpercode(jsonNode.get("opercode").getIntValue());
                    su.setText(jsonNode.get("text").getTextValue());
                    su.setTime(new Date(jsonNode.get("time").getLongValue()));
                    suList.add(su);
                }
                kdl.setDialogList(suList);
                kdl.setRetcode(pagesize);
            } else if (ifjson.has("errcode")) {
                throw new WeixinMessageException(ifjson.get("errcode").getIntValue());
            }
        } catch (MalformedURLException ex) {
            ex.printStackTrace();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
        return kdl;
    }

    /**
     * 获取素材总数
     *
     * @return MaterialCount 里面是四种素材每种素材的数量
     * @throws WeixinMessageException
     */
    public MaterialCount getMaterialCount() throws WeixinMessageException {
        MaterialCount mc = null;
        try {
            String url = "https://api.weixin.qq.com/cgi-bin/material/get_materialcount?access_token=" + this.getAccessTokenFromCache();
            StringBuilder sb = new StringBuilder();
            URL url1 = new URL(url);
            HttpURLConnection conn = (HttpURLConnection) url1.openConnection();
            conn.setRequestMethod("POST");
            conn.setConnectTimeout(10000);// 设置连接主机超时（单位：毫秒）
            conn.setReadTimeout(10000);// 设置从主机读取数据超时（单位：毫秒）
            conn.setDoOutput(true);
            conn.connect();
            BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"));
            String str;
            while ((str = br.readLine()) != null) {
                sb.append(str);
            }
            br.close();
            ObjectMapper objectMapper = new ObjectMapper();
            JsonNode ifjson = objectMapper.readTree(sb.toString());
            if (ifjson.has("voice_count")) {
                mc = new MaterialCount();
                int voiceCount = ifjson.get("voice_count").getIntValue();
                int videoCount = ifjson.get("video_count").getIntValue();
                int imageCount = ifjson.get("image_count").getIntValue();
                int newsCount = ifjson.get("news_count").getIntValue();
                mc.setImageCount(imageCount);
                mc.setNewsCount(newsCount);
                mc.setVideoCount(videoCount);
                mc.setVoiceCount(voiceCount);
            } else if (ifjson.has("errcode")) {
                throw new WeixinMessageException(ifjson.get("errcode").getIntValue());
            }
        } catch (MalformedURLException ex) {
            ex.printStackTrace();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
        return mc;
    }

    /**
     * 获取所有图文素材的接口
     *
     * @param offset 数据的偏移量 从0开始
     * @param count 每页获取的数据量 1 - 20之间
     * @return
     * @throws WeixinMessageException
     */
    public MaterialNewsList getMaterialNewsList(int offset, int count) throws WeixinMessageException {
        MaterialNewsList mnl = null;
        try {
            ObjectNode json = new ObjectNode(JsonNodeFactory.instance);
            json.put("type", "news");
            json.put("offset", offset);
            json.put("count", count);
            String url = "https://api.weixin.qq.com/cgi-bin/material/batchget_material?access_token=" + this.getAccessTokenFromCache();
            StringBuilder sb = new StringBuilder();
            URL url1 = new URL(url);
            HttpURLConnection conn = (HttpURLConnection) url1.openConnection();
            conn.setRequestMethod("POST");
            conn.setConnectTimeout(10000);// 设置连接主机超时（单位：毫秒）
            conn.setReadTimeout(10000);// 设置从主机读取数据超时（单位：毫秒）
            conn.setDoOutput(true);
            OutputStream os = conn.getOutputStream();
            conn.connect();
            os.write(json.toString().getBytes());
            BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"));
            String str;
            while ((str = br.readLine()) != null) {
                sb.append(str);
            }
            br.close();
//            System.err.println(sb);
            ObjectMapper objectMapper = new ObjectMapper();
            JsonNode ifjson = objectMapper.readTree(sb.toString());
            if (ifjson.has("total_count")) {
                mnl = new MaterialNewsList();
                int totalCount = ifjson.get("total_count").getIntValue();
                int itemCount = ifjson.get("item_count").getIntValue();
                mnl.setItemCount(itemCount);
                mnl.setTotalCount(totalCount);

                List<MaterialNews> suList = new LinkedList<MaterialNews>();
                JsonNode get = ifjson.get("item");
                //遍历素有的图文素材
                for (JsonNode jsonNode : get) {
                    MaterialNews mn = new MaterialNews();
                    mn.setMediaId(jsonNode.get("media_id").getTextValue());
                    mn.setUpdateTime(new Date(jsonNode.get("update_time").getLongValue()));
                    List<MaterialNews.Article> aList = new LinkedList();
                    mn.setArticles(aList);
                    //便利图文下面所有的条目
                    for (JsonNode jsonNode1 : jsonNode.get("content").get("news_item")) {
                        MaterialNews.Article asd = mn.new Article();
                        String title = jsonNode1.get("title").getTextValue();
                        String thumbMediaId = jsonNode1.get("thumb_media_id").getTextValue();
                        String thumbUrl = jsonNode1.get("thumb_url").getTextValue();
                        int showCoverPic = jsonNode1.get("show_cover_pic").getIntValue();
                        String author = jsonNode1.get("author").getTextValue();
                        String digest = jsonNode1.get("digest").getTextValue();
                        String content = jsonNode1.get("content").getTextValue();
                        String mUrl = jsonNode1.get("url").getTextValue();
                        String contentSourceUrl = jsonNode1.get("content_source_url").getTextValue();
                        asd.setAuthor(author);
                        asd.setContent(content);
                        asd.setContentSourceUrl(contentSourceUrl);
                        asd.setDigest(digest);
                        asd.setShowCoverPic(showCoverPic);
                        asd.setThumbMediaId(thumbMediaId);
                        asd.setThumbUrl(thumbUrl);
                        asd.setTitle(title);
                        asd.setUrl(mUrl);
                        aList.add(asd);
                    }
                    suList.add(mn);
                }
                mnl.setItemList(suList);
            } else if (ifjson.has("errcode")) {
                throw new WeixinMessageException(ifjson.get("errcode").getIntValue());
            }
        } catch (MalformedURLException ex) {
            ex.printStackTrace();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
        return mnl;
    }

    /**
     * 根据素材类型获取永久素材的列表
     *
     * @param offset
     * @param count
     * @param type
     * @return
     * @throws WeixinMessageException
     */
    public MaterialOthers getMaterialList(int offset, int count, MaterialType type) throws WeixinMessageException {
        MaterialOthers mnl = null;
        try {
            ObjectNode json = new ObjectNode(JsonNodeFactory.instance);
            json.put("type", type.getValue());
            json.put("offset", offset);
            json.put("count", count);
            String url = "https://api.weixin.qq.com/cgi-bin/material/batchget_material?access_token=" + this.getAccessTokenFromCache();
            StringBuilder sb = new StringBuilder();
            URL url1 = new URL(url);
            HttpURLConnection conn = (HttpURLConnection) url1.openConnection();
            conn.setRequestMethod("POST");
            conn.setConnectTimeout(10000);// 设置连接主机超时（单位：毫秒）
            conn.setReadTimeout(10000);// 设置从主机读取数据超时（单位：毫秒）
            conn.setDoOutput(true);
            OutputStream os = conn.getOutputStream();
            conn.connect();
            os.write(json.toString().getBytes());
            BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"));
            String str;
            while ((str = br.readLine()) != null) {
                sb.append(str);
            }
            br.close();
            ObjectMapper objectMapper = new ObjectMapper();
            JsonNode ifjson = objectMapper.readTree(sb.toString());
            if (ifjson.has("total_count")) {
                mnl = new MaterialOthers();
                int totalCount = ifjson.get("total_count").getIntValue();
                int itemCount = ifjson.get("item_count").getIntValue();
                mnl.setItemCount(itemCount);
                mnl.setTotalCount(totalCount);
                List<MaterialOther> suList = new LinkedList<MaterialOther>();
                JsonNode get = ifjson.get("item");
                for (JsonNode jsonNode : get) {
                    MaterialOther mo = new MaterialOther(type);
                    mo.setMediaId(jsonNode.get("media_id").getTextValue());
                    mo.setName(jsonNode.get("name").getTextValue());
                    mo.setUpdateTime(new Date(jsonNode.get("update_time").getLongValue()));
                    if (jsonNode.has("url")) {
                        mo.setUrl(jsonNode.get("url").getTextValue());
                    }
                    suList.add(mo);
                }
                mnl.setMeterialList(suList);
            } else if (ifjson.has("errcode")) {
                throw new WeixinMessageException(ifjson.get("errcode").getIntValue());
            }
        } catch (MalformedURLException ex) {
            ex.printStackTrace();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
        return mnl;
    }

    /**
     * 获取素材的地址
     *
     * @param mediaId
     * @return
     * @throws WeixinMessageException
     */
    public String getVideoMaterialUrl(String mediaId) throws WeixinMessageException {
        String mediaUrl = null;
        try {
            ObjectNode jsono = new ObjectNode(JsonNodeFactory.instance);
            jsono.put("media_id", mediaId);
            String url = "https://api.weixin.qq.com/cgi-bin/material/get_material?access_token=" + this.getAccessTokenFromCache();
            StringBuilder sb = new StringBuilder();
            URL url1 = new URL(url);
            HttpURLConnection conn = (HttpURLConnection) url1.openConnection();
            conn.setRequestMethod("POST");
            conn.setConnectTimeout(10000);// 设置连接主机超时（单位：毫秒）
            conn.setReadTimeout(10000);// 设置从主机读取数据超时（单位：毫秒）
            conn.setDoOutput(true);
            OutputStream os = conn.getOutputStream();
            conn.connect();
            os.write(jsono.toString().getBytes());
            BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"));
            String str;
            while ((str = br.readLine()) != null) {
                sb.append(str);
            }
            br.close();
            ObjectMapper objectMapper = new ObjectMapper();
            JsonNode ifjson = objectMapper.readTree(sb.toString());
            if (ifjson.has("down_url")) {
                mediaUrl = ifjson.get("down_url").getTextValue();
            } else if (ifjson.has("errcode")) {
                throw new WeixinMessageException(ifjson.get("errcode").getIntValue());
            }
        } catch (MalformedURLException ex) {
            ex.printStackTrace();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
        return mediaUrl;
    }

    /**
     * 只能获取 图片 和 音频 素材 通过素材的mediaId获取素材的文件流
     *
     * @param mediaId
     * @return
     * @throws WeixinMessageException
     */
    public HttpURLConnection getImgOrVoiceMaterial(String mediaId) throws WeixinMessageException {
        HttpURLConnection conn = null;
        try {
            ObjectNode jsono = new ObjectNode(JsonNodeFactory.instance);
            jsono.put("media_id", mediaId);
            String url = "https://api.weixin.qq.com/cgi-bin/material/get_material?access_token=" + this.getAccessTokenFromCache();
            URL url1 = new URL(url);
            conn = (HttpURLConnection) url1.openConnection();
            conn.setRequestMethod("POST");
            conn.setConnectTimeout(10000);// 设置连接主机超时（单位：毫秒）
            conn.setReadTimeout(10000);// 设置从主机读取数据超时（单位：毫秒）
            conn.setDoOutput(true);
            OutputStream os = conn.getOutputStream();
            conn.connect();
            os.write(jsono.toString().getBytes());
            return conn;
        } catch (MalformedURLException ex) {
            if (conn != null) {
                conn.disconnect();
            }
        } catch (IOException ex) {
            if (conn != null) {
                conn.disconnect();
            }
        }
        return null;
    }

//    public TempMaterial uploadTempMaterial(InputStream inputStream, String fileName, long fileLength,TempMaterial.MediaType type) throws WeixinMessageException {
//        TempMaterial tm = null;
//        StringBuilder sb = new StringBuilder();
//        String[] fileNameSp = fileName.split("\\.");
//        if (fileNameSp.length < 2) {
//            return null;
//        }
//        String urlStr = "https://api.weixin.qq.com/cgi-bin/media/upload?access_token=" + this.getAccessTokenFromCache() + "&type=" + type.getValue();
//        String BOUNDARY = "---------------------------" + System.currentTimeMillis();
//        // 请求正文信息  
//        // 第一部分：  
//        StringBuilder boundary = new StringBuilder();
////        boundary.append("Content-Type: multipart/form-data; boundary=").append(BOUNDARY).append("\r\n");
////        boundary.append("Content-Length: ").append(fileLength).append("\r\n").append("\r\n");
//        boundary.append(BOUNDARY).append("\r\n");
//        boundary.append("Content-Disposition: form-data;name=\"media\";filename=\"").append(fileName).append("\";").append("filelength=\"").append(fileLength).append("\"\r\n");
//        boundary.append("Content-Type:").append(type.getValue()).append("/").append(fileNameSp[1]).append("\r\n\r\n");
//        System.out.println(boundary);
//        try {
//            URL url = new URL(urlStr);
//            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
//            conn.setRequestMethod("POST");
//            conn.setConnectTimeout(10000);// 设置连接主机超时（单位：毫秒）
//            conn.setReadTimeout(10000);// 设置从主机读取数据超时（单位：毫秒）
//            conn.setDoOutput(true);
//            conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + BOUNDARY);
//            conn.setUseCaches(false); // post方式不能使用缓存  
//            // 设置请求头信息  
//            conn.setRequestProperty("Connection", "Keep-Alive");
//            conn.setRequestProperty("Charset", "UTF-8");
//            conn.connect();
//            OutputStream os = conn.getOutputStream();
//
//            byte[] b = new byte[1024 * 1024];
//            os.write(boundary.toString().getBytes("utf-8"));
//            while (true) {
//                int read = inputStream.read(b);
//                //判断是不是读到了数据流的末尾 ，防止出现死循环。  
//                if (read == -1) {
//                    break;
//                }
//                os.write(b);
//            }
//            os.write(("\r\n" + BOUNDARY + "--\r\n").getBytes("utf-8"));
//            inputStream.close();
//            os.close();
//            BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"));
//            String str;
//            while ((str = br.readLine()) != null) {
//                sb.append(str);
//            }
//            br.close();
//            conn.disconnect();
//            JsonNode ifjson = objectMapper.readTree(sb.toString());
//            if (ifjson.has("media_id")) {
//                tm = new TempMaterial();
//                tm.setType(MediaType.getMeiaByValue(ifjson.get("type").getTextValue()));
//                tm.setMediaId(ifjson.get("media_id").getTextValue());
//                tm.setCreatedAt(new Date(ifjson.get("created_at").getLongValue()));
//            } else if (ifjson.has("errcode")) {
//                throw new WeixinMessageException(ifjson.get("errcode").getIntValue());
//            }
//        } catch (MalformedURLException ex) {
//            ex.printStackTrace();
//        } catch (IOException ex) {
//            ex.printStackTrace();
//        }
//        return tm;
//    }
    public TempMaterial uploadTempMaterial(InputStream inputStream, String fileName, long fileLength, TempMaterial.MediaType type) throws WeixinMessageException {
        TempMaterial tm = null;
        try {
            // 拼装请求地址
            String uploadMediaUrl = "https://api.weixin.qq.com/cgi-bin/media/upload?access_token=" + this.getAccessTokenFromCache() + "&type=" + type.getValue();
            URL url = new URL(uploadMediaUrl);
            String result = null;
//            String suffix = fileName.substring(fileName.lastIndexOf("."), fileName.length());
            HttpURLConnection con = (HttpURLConnection) url.openConnection();
            con.setRequestMethod("POST"); // 以Post方式提交表单，默认get方式
            con.setDoInput(true);
            con.setDoOutput(true);
            con.setUseCaches(false); // post方式不能使用缓存
            // 设置请求头信息
            con.setRequestProperty("Connection", "Keep-Alive");
            con.setRequestProperty("Charset", "UTF-8");

            // 设置边界,这里的boundary是http协议里面的分割符
            String BOUNDARY = "----------" + System.currentTimeMillis();
            con.setRequestProperty("Content-Type",
                    "multipart/form-data; boundary=" + BOUNDARY);
            // 请求正文信息
            // 第一部分：
            StringBuilder sb = new StringBuilder();

            //这块是post提交type的值也就是文件对应的类型值
            sb.append("--").append(BOUNDARY); // 必须多两道线 http 协议头
            sb.append("\r\n");
            sb.append("Content-Disposition: form-data;name=\"type\" \r\n\r\n"); //这里是参数名，参数名和值之间要用两次
            sb.append(type.getValue()).append("\r\n"); //参数的值
            sb.append("--"); // 必须多两道线
            sb.append(BOUNDARY);
            sb.append("\r\n");
            //这里是media参数相关的信息
            sb.append("Content-Disposition: form-data;name=\"media\";filename=\"").append(fileName).append("\";filelength=\"").append(fileLength).append("\" \r\n");
            sb.append("Content-Type:application/octet-stream\r\n\r\n");
            byte[] head = sb.toString().getBytes("utf-8");
            // 获得输出流
            OutputStream out = new DataOutputStream(con.getOutputStream());
            // 输出表头
            out.write(head);
            // 文件正文部分
            // 把文件已流文件的方式 推入到url中

            int bytes = 0;
            byte[] bufferOut = new byte[1024];
            while ((bytes = inputStream.read(bufferOut)) != -1) {
                out.write(bufferOut, 0, bytes);
            }
            inputStream.close();
            // 结尾部分，这里结尾表示整体的参数的结尾，结尾要用"--"作为结束，这些都是http协议的规定
            byte[] foot = ("\r\n--" + BOUNDARY + "--\r\n").getBytes("utf-8");// 定义最后数据分隔线
            out.write(foot);
            out.flush();
            out.close();
            StringBuilder buffer = new StringBuilder();
            BufferedReader reader = null;
            // 定义BufferedReader输入流来读取URL的响应
            reader = new BufferedReader(new InputStreamReader(
                    con.getInputStream(), "utf-8"));
            String line = null;
            while ((line = reader.readLine()) != null) {
                buffer.append(line);
            }
            if (result == null) {
                result = buffer.toString();
            }
            // 使用JSONNode解析返回结果
            ObjectMapper objectMapper = new ObjectMapper();
            JsonNode ifjson = objectMapper.readTree(result);
            if (ifjson.has("media_id")) {
                tm = new TempMaterial();
                tm.setType(MediaType.getMeiaByValue(ifjson.get("type").getTextValue()));
                tm.setMediaId(ifjson.get("media_id").getTextValue());
                tm.setCreatedAt(new Date(ifjson.get("created_at").getLongValue()));
            } else if (ifjson.has("errcode")) {
                throw new WeixinMessageException(ifjson.get("errcode").getIntValue());
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {

        }
        return tm;
    }

    public JsonNode getCurrentAutoreplyInf() throws WeixinMessageException {
        JsonNode jsono = null;
        try {
            String url = "https://api.weixin.qq.com/cgi-bin/get_current_autoreply_info?access_token=" + this.getAccessTokenFromCache();
            StringBuilder sb = new StringBuilder();
            URL url1 = new URL(url);
            HttpURLConnection conn = (HttpURLConnection) url1.openConnection();
            conn.setRequestMethod("POST");
            conn.setConnectTimeout(10000);// 设置连接主机超时（单位：毫秒）
            conn.setReadTimeout(10000);// 设置从主机读取数据超时（单位：毫秒）
            conn.setDoOutput(true);
            conn.connect();
            BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"));
            String str;
            while ((str = br.readLine()) != null) {
                sb.append(str);
            }
            br.close();
            ObjectMapper objectMapper = new ObjectMapper();
            JsonNode ifjson = objectMapper.readTree(sb.toString());
            if (ifjson.has("errcode")) {
                throw new WeixinMessageException(ifjson.get("errcode").getIntValue());
            } else {
                jsono = ifjson;
            }
        } catch (IOException e) {
        }
        return jsono;
    }

}
